<div id="app" class="container">
  <h1 class="my-4">Configuration</h1>
  <div class="form" v-if="config">
    <!--Header-->
    <ul class="nav nav-tabs">
      <li class="nav-item" v-for="tab in tabs" :key="tab.id">
        <a
          class="nav-link"
          :class="{'active': tab.id === currentTab}"
          href="#"
          @click="currentTab = tab.id"
          >{{tab.name}}</a
        >
      </li>
    </ul>
    <!--General Tab-->
    <div v-if="currentTab === 'general'" class="config-page">
      <!--Sunshine Name-->
      <div class="mb-3">
        <label for="sunshine_name" class="form-label">Sunshine Name</label>
        <input
          type="text"
          class="form-control"
          id="sunshine_name"
          placeholder="Sunshine"
          v-model="config.sunshine_name"
        />
        <div class="form-text">
          The name displayed by Moonlight. If not specified, the PC's hostname is used
        </div>
      </div>
      <!--Log Level-->
      <div class="mb-3">
        <label for="min_log_level" class="form-label">Log Level</label>
        <select
          id="min_log_level"
          class="form-select"
          v-model="config.min_log_level"
        >
          <option value="0">Verbose</option>
          <option value="1">Debug</option>
          <option value="2">Info</option>
          <option value="3">Warning</option>
          <option value="4">Error</option>
          <option value="5">Fatal</option>
          <option value="6">None</option>
        </select>
        <div class="form-text">
          The minimum log level printed to standard out
        </div>
      </div>
      <!--Log Path-->
      <div class="mb-3">
        <label for="log_path" class="form-label">Logfile Path</label>
        <input
          type="text"
          class="form-control"
          id="log_path"
          placeholder="sunshine.log"
          v-model="config.log_path"
        />
        <div class="form-text">
          The file where the current logs of Sunshine are stored.
        </div>
      </div>
      <!--Origin Web UI Allowed-->
      <div class="mb-3">
        <label for="origin_web_ui_allowed" class="form-label"
          >Origin Web UI Allowed</label
        >
        <select
          id="origin_web_ui_allowed"
          class="form-select"
          v-model="config.origin_web_ui_allowed"
          @change="forceUpdate"
        >
          <option value="pc">Only localhost may access Web UI</option>
          <option value="lan">Only those in LAN may access Web UI</option>
          <option value="wan">Anyone may access Web UI</option>
        </select>
        <div class="form-text">
          The origin of the remote endpoint address that is not denied access to Web UI
        </div>
        <!-- add warning about exposing web ui to the internet -->
        <div class="alert alert-danger" v-if="config.origin_web_ui_allowed === 'wan'">
          <i class="fa-solid fa-xl fa-triangle-exclamation"></i> Exposing the Web UI to the internet is a security risk! Proceed at your own risk!
        </div>
      </div>
      <!--UPnP-->
      <div class="mb-3">
        <label for="upnp" class="form-label">UPnP</label>
        <select id="upnp" class="form-select" v-model="config.upnp">
          <option value="disabled">Disabled</option>
          <option value="enabled">Enabled</option>
        </select>
        <div class="form-text">Automatically configure port forwarding</div>
      </div>
      <!--Gamepads-->
      <div class="mb-3" v-if="platform === 'windows'">
        <label for="gamepad" class="form-label">Gamepads</label>
        <select id="gamepad" class="form-select" v-model="config.gamepad">
          <option value="auto">Automatic</option>
          <option value="ds4">DS4 (PS4)</option>
          <option value="x360">X360 (Xbox 360)</option>
        </select>
        <div class="form-text">Choose which type of gamepad to emulate on the host</div>
      </div>
      <!--Ping Timeout-->
      <div class="mb-3">
        <label for="ping_timeout" class="form-label">Ping Timeout</label>
        <input
          type="text"
          class="form-control"
          id="ping_timeout"
          placeholder="10000"
          v-model="config.ping_timeout"
        />
        <div class="form-text">
          How long to wait in milliseconds for data from moonlight before shutting down the stream
        </div>
      </div>
      <!--Advertised FPS and Resolutions-->
      <div class="mb-3">
        <label for="ping_timeout" class="form-label"
          >Advertised Resolutions and FPS</label
        >
        <div class="resolutions-container">
          <label>Resolutions</label>
          <div class="resolutions d-flex flex-wrap">
            <div
              class="p-2 ms-item m-2 d-flex justify-content-between"
              v-for="(r,i) in resolutions"
              :key="r"
            >
              <span class="px-2">{{r}}</span>
              <span style="cursor: pointer" @click="resolutions.splice(i,1)"
                >&times;</span
              >
            </div>
            <form
              @submit.prevent="resolutions.push(resIn);resIn = '';"
              class="d-flex align-items-center"
            >
              <input
                type="text"
                v-model="resIn"
                required
                pattern="[0-9]+x[0-9]+"
                style="
                  border-top-right-radius: 0;
                  border-bottom-right-radius: 0;
                "
                class="form-control"
              />
              <button
                style="border-top-left-radius: 0; border-bottom-left-radius: 0"
                class="btn btn-success"
              >
                +
              </button>
            </form>
          </div>
        </div>
        <div class="fps-container">
          <label>FPS</label>
          <div class="fps d-flex flex-wrap">
            <div
              class="p-2 ms-item m-2 d-flex justify-content-between"
              v-for="(f,i) in fps"
              :key="f"
            >
              <span class="px-2">{{f}}</span>
              <span style="cursor: pointer" @click="fps.splice(i,1)"
                >&times;</span
              >
            </div>
            <form
              @submit.prevent="fps.push(fpsIn);fpsIn = '';"
              class="d-flex align-items-center"
            >
              <input
                type="text"
                v-model="fpsIn"
                required
                pattern="[0-9]+"
                style="
                  width: 6ch;
                  border-top-right-radius: 0;
                  border-bottom-right-radius: 0;
                "
                class="form-control"
              />
              <button
                style="border-top-left-radius: 0; border-bottom-left-radius: 0"
                class="btn btn-success"
              >
                +
              </button>
            </form>
          </div>
        </div>
        <div class="form-text">
          The display modes advertised by Sunshine<br />
          Some versions of Moonlight, such as Moonlight-nx (Switch), rely on this list to ensure that the requested
          resolutions and fps are supported.<br>
          This setting does <b>not</b> change how the screen stream is sent to Moonlight
        </div>
      </div>
      <!-- Mapping Key AltRight to Key Windows -->
      <div class="mb-3">
        <label for="mapkey" class="form-label"
          >Map Right Alt key to Windows key</label
        >
        <select
          id="mapkey"
          class="form-select"
          v-model="config.key_rightalt_to_key_win"
        >
          <option value="disabled">Disabled</option>
          <option value="enabled">Enabled</option>
        </select>
        <div class="form-text">
          It may be possible that you cannot send the Windows Key from Moonlight directly.<br />
          In those cases it may be useful to make Sunshine think the Right Alt key is the Windows key
        </div>
      </div>
      <!-- Global Prep Commands -->
      <div class="mb-3 d-flex flex-column">
        <label class="form-label">Command Preparations</label>
        <div class="form-text">
          Configure a list of commands to be executed before or after running any application. 
          If any of the specified preparation commands fail, the application launch process will be aborted.
        </div>
        <table class="table" v-if="global_prep_cmd.length > 0">
          <thead>
            <tr>
              <th scope="col"><i class="fas fa-play"></i> Do Command</th>
              <th scope="col"><i class="fas fa-undo"></i> Undo Command</th>
              <th scope="col" v-if="platform === 'windows'">
                <i class="fas fa-shield-alt"></i> Run as Admin
              </th>
              <th scope="col"></th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(c, i) in global_prep_cmd">
              <td>
                <input type="text" class="form-control monospace" v-model="c.do" />
              </td>
              <td>
                <input type="text" class="form-control monospace" v-model="c.undo" />
              </td>
              <td v-if="platform === 'windows'">
                <div class="form-check">
                  <input
                    type="checkbox"
                    class="form-check-input"
                    :id="'prep-cmd-admin-' + i"
                    v-model="c.elevated"
                    true-value="true"
                    false-value="false"
                  />
                  <label :for="'prep-cmd-admin-' + i" class="form-check-label"
                    >Elevated</label
                  >
                </div>
              </td>
              <td>
                <button class="btn btn-danger" @click="$delete(global_prep_cmd, i)">
                  <i class="fas fa-trash"></i>
                </button>
                <button class="btn btn-success" @click="add_global_prep_cmd">
                  <i class="fas fa-plus"></i>
                </button>
              </td>
            </tr>
          </tbody>
        </table>              
        <button class="mt-2 btn btn-success" style="margin: 0 auto" @click="add_global_prep_cmd">
          &plus; Add
        </button>
      </div>
    </div>
    <!--Files Tab-->
    <div v-if="currentTab === 'files'" class="config-page">
      <!--Private Key-->
      <div class="mb-3">
        <label for="pkey" class="form-label">Private Key</label>
        <input
          type="text"
          class="form-control"
          id="pkey"
          placeholder="/dir/pkey.pem"
          v-model="config.pkey"
        />
        <div class="form-text">The private key must be 2048 bits</div>
      </div>
      <!--Cert-->
      <div class="mb-3">
        <label for="cert" class="form-label">Cert</label>
        <input
          type="text"
          class="form-control"
          id="cert"
          placeholder="/dir/cert.pem"
          v-model="config.cert"
        />
        <div class="form-text">
          The certificate must be signed with a 2048 bit key
        </div>
      </div>

      <!--State File-->
      <div class="mb-3">
        <label for="file_state" class="form-label">State File</label>
        <input
          type="text"
          class="form-control"
          id="file_state"
          placeholder="sunshine_state.json"
          v-model="config.file_state"
        />
        <div class="form-text">
          The file where current state of Sunshine is stored
        </div>
      </div>
      <!--Apps File-->
      <div class="mb-3">
        <label for="file_apps" class="form-label">Apps File</label>
        <input
          type="text"
          class="form-control"
          id="file_apps"
          placeholder="apps.json"
          v-model="config.file_apps"
        />
        <div class="form-text">
          The file where current apps of Sunshine are stored
        </div>
      </div>
    </div>
    <div v-if="currentTab === 'input'" class="config-page">
      <!--Home/Guide Button Emulation Timeout-->
      <div class="mb-3">
        <label for="back_button_timeout" class="form-label"
          >Home/Guide Button Emulation Timeout</label
        >
        <input
          type="text"
          class="form-control"
          id="back_button_timeout"
          placeholder="-1"
          v-model="config.back_button_timeout"
        />
        <div class="form-text">
          If the Back/Select button is held down for the specified number of milliseconds, a Home/Guide button press is emulated.<br />
          If set to a value &lt; 0 (default), holding the Back/Select button will not emulate the Home/Guide button.<br />
        </div>
      </div>
      <!--Enable Mouse Input-->
      <div class="mb-3">
        <label for="mouse" class="form-label"
          >Enable Mouse Input</label
        >
        <select
          id="mouse"
          class="form-select"
          v-model="config.mouse"
        >
          <option value="disabled">Disabled</option>
          <option value="enabled">Enabled</option>
        </select>
        <div class="form-text">
          Allows guests to control the host system with the mouse
        </div>
      </div>
      <!--Enable Keyboard Input-->
      <div class="mb-3">
        <label for="keyboard" class="form-label"
          >Enable Keyboard Input</label
        >
        <select
          id="keyboard"
          class="form-select"
          v-model="config.keyboard"
        >
          <option value="disabled">Disabled</option>
          <option value="enabled">Enabled</option>
        </select>
        <div class="form-text">
          Allows guests to control the host system with the keyboard
        </div>
      </div>
      <!--Enable Gamepad Input-->
      <div class="mb-3">
        <label for="gamepad" class="form-label"
          >Enable Gamepad Input</label
        >
        <select
          id="gamepad"
          class="form-select"
          v-model="config.controller"
        >
          <option value="disabled">Disabled</option>
          <option value="enabled">Enabled</option>
        </select>
        <div class="form-text">
          Allows guests to control the host system with a gamepad / controller
        </div>
      </div>
      <!-- Key Repeat Delay-->
      <div class="mb-3" v-if="platform === 'windows'">
        <label for="key_repeat_delay" class="form-label"
          >Key Repeat Delay</label
        >
        <input
          type="text"
          class="form-control"
          id="key_repeat_delay"
          placeholder="500"
          v-model="config.key_repeat_delay"
        />
        <div class="form-text">
          Control how fast keys will repeat themselves<br />
          The initial delay in milliseconds before repeating keys
        </div>
      </div>
      <!-- Key Repeat Frequency-->
      <div class="mb-3" v-if="platform === 'windows'">
        <label for="key_repeat_frequency" class="form-label"
          >Key Repeat Frequency</label
        >
        <input
          type="text"
          class="form-control"
          id="key_repeat_frequency"
          placeholder="24.9"
          v-model="config.key_repeat_frequency"
        />
        <div class="form-text">
          How often keys repeat every second<br />
          This configurable option supports decimals
        </div>
      </div>
      <!-- Always send scancodes -->
      <div class="mb-3" v-if="platform === 'windows'">
        <label for="always_send_scancodes" class="form-label"
          >Always Send Scancodes</label
        >
        <select
          id="always_send_scancodes"
          class="form-select"
          v-model="config.always_send_scancodes"
        >
          <option value="disabled">Disabled</option>
          <option value="enabled">Enabled</option>
        </select>
        <div class="form-text">
          Sending scancodes enhances compatibility with games and apps
          but may result in incorrect keyboard input from certain clients
          that aren't using a US English keyboard layout.<br />
          Enable if keyboard input is not working at all in certain applications.<br />
          Disable if keys on the client are generating the wrong input on the host.
        </div>
      </div>
    </div>
    <!--Files Tab-->
    <div v-if="currentTab === 'av'" class="config-page">
      <!--Audio Sink-->
      <div class="mb-3" v-if="platform === 'windows'">
        <label for="audio_sink" class="form-label">Audio Sink</label>
        <input
          type="text"
          class="form-control"
          id="audio_sink"
          placeholder="Speakers (High Definition Audio Device)"
          v-model="config.audio_sink"
        />
        <div class="form-text">
          Manually specify a specific audio device to capture. If unset, the device is chosen automatically.<br />
          <b>We strongly recommend leaving this field blank to use automatic device selection!</b><br />
          If you have multiple audio devices with identical names, you can get the Device ID using the following command:<br />
          <pre>tools\audio-info.exe</pre>
        </div>
      </div>
      <div class="mb-3" v-if="platform === 'linux'">
        <label for="audio_sink" class="form-label">Audio Sink</label>
        <input
          type="text"
          class="form-control"
          id="audio_sink"
          placeholder="alsa_output.pci-0000_09_00.3.analog-stereo"
          v-model="config.audio_sink"
        />
        <div class="form-text">
          The name of the audio sink used for Audio Loopback<br />
          If you do not specify this variable, pulseaudio will select the default monitor device.<br />
          <br />
          You can find the name of the audio sink using either command:<br />
          <pre>pacmd list-sinks | grep "name:"</pre>
          <pre>pactl info | grep Source</pre>
          <br />
        </div>
      </div>
      <div class="mb-3" v-if="platform === 'macos'">
        <label for="audio_sink" class="form-label">Audio Sink</label>
        <input
          type="text"
          class="form-control"
          id="audio_sink"
          placeholder="BlackHole 2ch"
          v-model="config.audio_sink"
        />
        <div class="form-text">
          The name of the audio sink used for Audio Loopback<br />
          Sunshine can only access microphones on macOS due to system limitations.<br />
          To stream system audio using <a
            href="https://github.com/mattingalls/Soundflower"
            target="_blank">
            Soundflower
          </a> or <a
            href="https://github.com/ExistentialAudio/BlackHole"
            target="_blank">
            BlackHole
          </a>.
        </div>
      </div>
      <!--Virtual Sink-->
      <div class="mb-3" v-if="platform === 'windows'">
        <label for="virtual_sink" class="form-label">Virtual Sink</label>
        <input
          type="text"
          class="form-control"
          id="virtual_sink"
          placeholder="Steam Streaming Speakers"
          v-model="config.virtual_sink"
        />
        <div class="form-text">
          Manually specify a virtual audio device to use. If unset, the device is chosen automatically.<br />
          <b>We strongly recommend leaving this field blank to use automatic device selection!</b><br />
        </div>
      </div>
      <!--Install Steam Audio Drivers-->
      <div class="mb-3" v-if="platform === 'windows'">
        <label for="install_steam_audio_drivers" class="form-label">Install Steam Audio Drivers</label>
        <select id="install_steam_audio_drivers" class="form-select" v-model="config.install_steam_audio_drivers">
          <option value="disabled">Disabled</option>
          <option value="enabled">Enabled</option>
        </select>
        <div class="form-text">
          If Steam is installed, this will automatically install the Steam Streaming Speakers driver to support
          5.1/7.1 surround sound and muting host audio.
        </div>
      </div>
      <!--Adapter Name -->
      <div class="mb-3" v-if="platform === 'windows'">
        <label for="adapter_name" class="form-label">Adapter Name</label>
        <input
          type="text"
          class="form-control"
          id="adapter_name"
          placeholder="Radeon RX 580 Series"
          v-model="config.adapter_name"
        />
        <div class="form-text" v-if="platform === 'windows'">
          Manually specify a GPU to use for capture. If unset, the GPU is chosen automatically.<br />
          <b>We strongly recommend leaving this field blank to use automatic GPU selection!</b><br />
          Note: This GPU must have a display connected and powered on.<br />
          The appropriate values can be found using the following command:<br />
          <pre>tools\dxgi-info.exe</pre>
        </div>
      </div>
      <!--Output Name -->
      <div class="mb-3" v-if="platform === 'windows'">
        <label for="output_name" class="form-label">Output Name</label>
        <input
          type="text"
          class="form-control"
          id="output_name"
          placeholder="\\.\DISPLAY1"
          v-model="config.output_name"
        />
        <div class="form-text">
          Manually specify a display to use for capture. If unset, the primary display is captured.<br />
          Note: If you specified a GPU above, this display must be connected to that GPU.<br />
          The appropriate values can be found using the following command:<br />
          tools\dxgi-info.exe<br />
        </div>
      </div>
      <div class="mb-3" v-if="platform === 'linux'">
        <label for="output_name" class="form-label">Monitor number</label>
        <input
          type="text"
          class="form-control"
          id="output_name"
          placeholder="0"
          v-model="config.output_name"
        />
        <div class="form-text">
          During Sunshine startup, you should see the list of detected monitors, e.g.:<br />
          <br />
          <pre style="white-space: pre-line;">
            Info: Detecting connected monitors
            Info: Detected monitor 0: DVI-D-0, connected: false
            Info: Detected monitor 1: HDMI-0, connected: true
            Info: Detected monitor 2: DP-0, connected: true
            Info: Detected monitor 3: DP-1, connected: false
            Info: Detected monitor 4: DVI-D-1, connected: false
          </pre>
          You need to use the value before the colon in the output, e.g. <b>1</b>.
        </div>
      </div>
    </div>
    <div v-if="currentTab === 'advanced'" class="config-page">
      <!--Address family-->
      <div class="mb-3">
        <label for="address_family" class="form-label">Address Family</label>
        <select
          id="address_family"
          class="form-select"
          v-model="config.address_family"
        >
          <option value="ipv4">IPv4 only</option>
          <option value="both">IPv4+IPv6</option>
        </select>
        <div class="form-text">Set the address family used by Sunshine</div>
      </div>
      <!--Port family-->
      <div class="mb-3">
        <label for="port" class="form-label">Port</label>
        <input
          type="number"
          min="1029"
          max="65514"
          class="form-control"
          id="port"
          placeholder="47989"
          v-model="config.port"
        />
        <div class="form-text">Set the family of ports used by Sunshine</div>
        <!-- Add warning if any port is less than 1024 -->
        <div class="alert alert-danger" v-if="(+effectivePort - 5) < 1024">
          <i class="fa-solid fa-xl fa-triangle-exclamation"></i> Sunshine cannot use ports below 1024!
        </div>
        <!-- Add warning if any port is above 65535 -->
        <div class="alert alert-danger" v-if="(+effectivePort + 21) > 65535">
          <i class="fa-solid fa-xl fa-triangle-exclamation"></i> Ports above 65535 are not available!
        </div>
        <!-- Create a port table for the various ports needed by Sunshine -->
        <table class="table">
          <thead>
            <tr>
              <th scope="col">Protocol</th>
              <th scope="col">Port</th>
              <th scope="col">Note</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <!-- HTTPS -->
              <td>TCP</td>
              <td>{{+effectivePort - 5}}</td>
              <td></td>
            </tr>
            <tr>
              <!-- HTTP -->
              <td>TCP</td>
              <td>{{+effectivePort}}</td>
              <td>
                <div class="alert alert-primary" role="alert" v-if="+effectivePort !== 47989">
                  <i class="fa-solid fa-xl fa-circle-info"></i> Use this port to connect with Moonlight.
                </div>
              </td>
            </tr>
            <tr>
              <!-- Web UI -->
              <td>TCP</td>
              <td>{{+effectivePort + 1}}</td>
              <td>Web UI</td>
            </tr>
            <tr>
              <!-- RTSP -->
              <td>TCP</td>
              <td>{{+effectivePort + 21}}</td>
              <td></td>
            </tr>
            <tr>
              <!-- Video, Control, Audio -->
              <td>UDP</td>
              <td>{{+effectivePort + 9}} - {{+effectivePort + 11}}</td>
              <td></td>
            </tr>
<!--            <tr>-->
<!--              &lt;!&ndash; Mic &ndash;&gt;-->
<!--              <td>UDP</td>-->
<!--              <td>{{+effectivePort + 13}}</td>-->
<!--              <td></td>-->
<!--            </tr>-->
          </tbody>
        </table>
        <!-- add warning about exposing web ui to the internet -->
        <div class="alert alert-warning" v-if="config.origin_web_ui_allowed === 'wan'">
          <i class="fa-solid fa-xl fa-triangle-exclamation"></i> Exposing the Web UI to the internet is a security risk!
          Proceed at your own risk!
        </div>
      </div>
      <!-- Quantization Parameter -->
      <div class="mb-3">
        <label for="qp" class="form-label">Quantization Parameter</label>
        <input
          type="number"
          class="form-control"
          id="qp"
          placeholder="28"
          v-model="config.qp"
        />
        <div class="form-text">
          Quantization Parameter<br />
          Some devices may not support Constant Bit Rate.<br />
          For those devices, QP is used instead.<br />
          Higher value means more compression, but less quality<br />
        </div>
      </div>
      <!-- Min Threads -->
      <div class="mb-3">
        <label for="min_threads" class="form-label"
          >Minimum Software Encoding Thread Count</label
        >
        <input
          type="number"
          min="1"
          class="form-control"
          id="min_threads"
          placeholder="1"
          v-model="config.min_threads"
        />
        <div class="form-text">
          Increasing the value slightly reduces encoding efficiency, but the tradeoff is usually<br />
          worth it to gain the use of more CPU cores for encoding. The ideal value is the lowest<br />
          value that can reliably encode at your desired streaming settings on your hardware.
        </div>
      </div>
      <!--HEVC Support -->
      <div class="mb-3">
        <label for="hevc_mode" class="form-label">HEVC Support</label>
        <select id="hevc_mode" class="form-select" v-model="config.hevc_mode">
          <option value="0">
            Sunshine will advertise support for HEVC based on encoder capabilities (recommended)
          </option>
          <option value="1">
            Sunshine will not advertise support for HEVC
          </option>
          <option value="2">
            Sunshine will advertise support for HEVC Main profile
          </option>
          <option value="3">
            Sunshine will advertise support for HEVC Main and Main10 (HDR) profiles
          </option>
        </select>
        <div class="form-text">
          Allows the client to request HEVC Main or HEVC Main10 video streams.<br />
          HEVC is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding.
        </div>
      </div>
      <!--AV1 Support -->
      <div class="mb-3">
        <label for="av1_mode" class="form-label">AV1 Support</label>
        <select id="av1_mode" class="form-select" v-model="config.av1_mode">
          <option value="0">
            Sunshine will advertise support for AV1 based on encoder capabilities (recommended)
          </option>
          <option value="1">
            Sunshine will not advertise support for AV1
          </option>
          <option value="2">
            Sunshine will advertise support for AV1 Main 8-bit profile
          </option>
          <option value="3">
            Sunshine will advertise support for AV1 Main 8-bit and 10-bit (HDR) profiles
          </option>
        </select>
        <div class="form-text">
          Allows the client to request AV1 Main 8-bit or 10-bit video streams.<br />
          AV1 is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding.
        </div>
      </div>
      <!--Capture-->
      <div class="mb-3" v-if="platform === 'linux'">
        <label for="capture" class="form-label">Force a Specific Capture Method</label>
        <select id="capture" class="form-select" v-model="config.capture">
          <option value="">Autodetect</option>
          <option value="nvfbc">NvFBC</option>
          <option value="wlr">wlroots</option>
          <option value="kms">KMS</option>
          <option value="x11">X11</option>
        </select>
        <div class="form-text">
          Force a specific capture method, otherwise Sunshine will use the first one that works. NvFBC requires patched nvidia drivers.
        </div>
      </div>
      <!--Encoder-->
      <div class="mb-3">
        <label for="encoder" class="form-label">Force a Specific Encoder</label>
        <select id="encoder" class="form-select" v-model="config.encoder">
          <option value="">Autodetect</option>
          <option value="nvenc" v-if="platform === 'windows' || platform === 'linux'">NVIDIA NVENC</option>
          <option value="quicksync" v-if="platform === 'windows'">Intel QuickSync</option>
          <option value="amdvce" v-if="platform === 'windows'">AMD AMF/VCE</option>
          <option value="vaapi" v-if="platform === 'linux'">VA-API</option>
          <option value="videotoolbox" v-if="platform === 'macos'">VideoToolbox</option>
          <option value="software">Software</option>
        </select>
        <div class="form-text">
          Force a specific encoder, otherwise Sunshine will use the first encoder that is available<br />
          Note: If you specify a hardware encoder on Windows, it must match the GPU where the display is connected.
        </div>
      </div>
      <!--FEC Percentage-->
      <div class="mb-3">
        <label for="fec_percentage" class="form-label">FEC Percentage</label>
        <input
          type="text"
          class="form-control"
          id="fec_percentage"
          placeholder="20"
          v-model="config.fec_percentage"
        />
        <div class="form-text">
          Percentage of error correcting packets per data packet in each video frame.<br />
          Higher values can correct for more network packet loss, but at the cost of increasing bandwidth usage.<br />
          The default value of 20 is what GeForce Experience uses.
        </div>
      </div>
      <!--Channels-->
      <div class="mb-3">
        <label for="channels" class="form-label">Channels</label>
        <input
          type="text"
          class="form-control"
          id="channels"
          placeholder="1"
          v-model="config.channels"
        />
        <div class="form-text">
          When multicasting, it could be useful to have different configurations for each connected Client. For example:
          <ul>
            <li>
              Clients connected through WAN and LAN have different bitrate constraints.
            </li>
            <li>
              Decoders may require different settings for color
            </li>
          </ul>
          Unlike simply broadcasting to multiple Client, this will generate distinct video streams.<br />
          Note, CPU usage increases for each distinct video stream generated
        </div>
      </div>
      <!--Credentials File-->
      <div class="mb-3">
        <label for="credentials_file" class="form-label"
          >Web Manager Credentials File</label
        >
        <input
          type="text"
          class="form-control"
          id="credentials_file"
          placeholder="sunshine_state.json"
          v-model="config.credentials_file"
        />
        <div class="form-text">
          Store Username/Password separately from Sunshine's state file.
        </div>
      </div>
      <!--External IP-->
      <div class="mb-3">
        <label for="external_ip" class="form-label">External IP</label>
        <input
          type="text"
          class="form-control"
          id="external_ip"
          placeholder="123.456.789.12"
          v-model="config.external_ip"
        />
        <div class="form-text">
          If no external IP address is given, Sunshine will automatically detect external IP
        </div>
      </div>
    </div>
    <!--Software Settings-->
    <div v-if="currentTab === 'sw'" class="config-page">
      <div class="mb-3">
        <label for="sw_preset" class="form-label">SW Presets</label>
        <select id="sw_preset" class="form-select" v-model="config.sw_preset">
          <option value="ultrafast">ultrafast</option>
          <option value="superfast">superfast (default)</option>
          <option value="veryfast">veryfast</option>
          <option value="faster">faster</option>
          <option value="fast">fast</option>
          <option value="medium">medium</option>
          <option value="slow">slow</option>
          <option value="slower">slower</option>
          <option value="veryslow">veryslow</option>
        </select>
        <div class="form-text">
          Optimize the trade-off between encoding speed (encoded frames per second) and compression efficiency (quality per bit in the bitstream). Defaults to superfast.
        </div>
      </div>
      <div class="mb-3">
        <label for="sw_tune" class="form-label">SW Tune</label>
        <select id="sw_tune" class="form-select" v-model="config.sw_tune">
          <option value="film">film -- use for high quality movie content; lowers deblocking</option>
          <option value="animation">animation -- good for cartoons; uses higher deblocking and more reference frames</option>
          <option value="grain">grain -- preserves the grain structure in old, grainy film material</option>
          <option value="stillimage">stillimage -- good for slideshow-like content</option>
          <option value="fastdecode">fastdecode -- allows faster decoding by disabling certain filters</option>
          <option value="zerolatency">zerolatency -- good for fast encoding and low-latency streaming (default)</option>
        </select>
        <div class="form-text">
          Tuning options, which are applied after the preset. Defaults to zerolatency.
        </div>
      </div>
    </div>
    <!--Nvidia Encoder Settings-->
    <div v-if="currentTab === 'nv'" class="config-page">
      <!--NVENC SETTINGS-->
      <div class="mb-3">
        <label for="nvenc_preset" class="form-label">Performance preset</label>
        <select id="nvenc_preset" class="form-select" v-model="config.nvenc_preset">
          <option value="1">P1 (fastest, default)</option>
          <option value="2">P2</option>
          <option value="3">P3</option>
          <option value="4">P4</option>
          <option value="5">P5</option>
          <option value="6">P6</option>
          <option value="7">P7 (slowest)</option>
        </select>
        <div class="form-text">Higher numbers improve compression (quality at given bitrate) at the cost of
          <strong>increased encoding latency</strong>.<br>
          Recommended to change only when limited by network or decoder, otherwise similar effect can be accomplished by
          increasing bitrate.
        </div>
      </div>
      <div class="mb-3">
        <label for="nvenc_twopass" class="form-label">Two-pass mode</label>
        <select id="nvenc_twopass" class="form-select" v-model="config.nvenc_twopass">
          <option value="disabled">Disabled (fastest, not recommended)</option>
          <option value="quarter_res">Quarter resolution (faster, default)</option>
          <option value="full_res">Full resolution (slower)</option>
        </select>
        <div class="form-text">Adds preliminary encoding pass.<br>
          This allows to detect more motion vectors, better distribute bitrate across the frame and more strictly adhere to
          bitrate limits.<br>
          Disabling it is not recommended since this can lead to occasional bitrate overshoot and subsequent packet loss.
        </div>
      </div>
      <div class="accordion">
        <div class="accordion-item">
          <h2 class="accordion-header">
            <button class="accordion-button" type="button" data-bs-toggle="collapse"
              data-bs-target="#panelsStayOpen-collapseOne">
              Miscellaneous options
            </button>
          </h2>
          <div id="panelsStayOpen-collapseOne" class="accordion-collapse collapse show"
            aria-labelledby="panelsStayOpen-headingOne">
            <div class="accordion-body">
              <div class="mb-3" v-if="platform === 'windows'">
                <label for="nvenc_realtime_hags" class="form-label">Use realtime priority in hardware accelerated gpu scheduling</label>
                <select id="nvenc_realtime_hags" class="form-select" v-model="config.nvenc_realtime_hags">
                  <option value="disabled">Disabled</option>
                  <option value="enabled">Enabled (default)</option>
                </select>
                <div class="form-text">Currently NVIDIA drivers may freeze in encoder when
                  <a href="https://devblogs.microsoft.com/directx/hardware-accelerated-gpu-scheduling/">HAGS</a>
                  is enabled, realtime priority is used and VRAM utilization is close to maximum.<br>
                  Disabling this option lowers the priority to high, sidestepping the freeze at the cost of reduced capture
                  performance when the GPU is heavily loaded.
                </div>
              </div>
              <div>
                <label for="nvenc_h264_cavlc" class="form-label">Prefer CAVLC over CABAC in H.264</label>
                <select id="nvenc_h264_cavlc" class="form-select" v-model="config.nvenc_h264_cavlc">
                  <option value="disabled">Disabled (default)</option>
                  <option value="enabled">Enabled</option>
                </select>
                <div class="form-text">Simpler form of entropy coding.<br>
                  CAVLC needs around 10% more bitrate for same quality.<br>
                  Only relevant for really old decoding devices.
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <!--Intel Encoder Settings-->
    <div v-if="currentTab === 'qsv'" class="config-page">
      <div class="mb-3">
        <label for="qsv_preset" class="form-label">QuickSync Preset</label>
        <select id="qsv_preset" class="form-select" v-model="config.qsv_preset">
          <option value="veryfast">fastest (lowest quality)</option>
          <option value="faster">faster (lower quality)</option>
          <option value="fast">fast (low quality)</option>
          <option value="medium">medium (default)</option>
          <option value="slow">slow (good quality)</option>
          <option value="slower">slower (better quality)</option>
          <option value="slowest">slowest (best quality)</option>
        </select>
      </div>
      <div class="mb-3">
        <label for="qsv_coder" class="form-label">QuickSync Coder (H264)</label>
        <select id="qsv_coder" class="form-select" v-model="config.qsv_coder">
          <option value="auto">auto -- let ffmpeg decide (default)</option>
          <option value="cabac">cabac -- context adaptive binary arithmetic coding - higher quality</option>
          <option value="cavlc">cavlc -- context adaptive variable-length coding - faster decode</option>
        </select>
      </div>
    </div>
    <!--AMD Encoder Settings-->
    <div v-if="currentTab === 'amd'" class="config-page">
      <!--Presets-->
      <div class="mb-3">
        <label for="amd_quality" class="form-label">AMF Quality</label>
        <select
          id="amd_quality"
          class="form-select"
          v-model="config.amd_quality">
          <option value="speed">speed -- prefer speed</option>
          <option value="balanced">balanced -- balanced (default)</option>
          <option value="quality">quality -- prefer quality</option>
        </select>
      </div>
      <div class="mb-3">
        <label for="amd_rc" class="form-label">AMF Rate Control</label>
        <select id="amd_rc" class="form-select" v-model="config.amd_rc">
          <option value="cqp">cqp -- constant qp mode</option>
          <option value="vbr_latency">vbr_latency -- latency constrained variable bitrate (default)</option>
          <option value="vbr_peak">vbr_peak -- peak constrained variable bitrate</option>
          <option value="cbr">cbr -- constant bitrate</option>
        </select>
      </div>
      <div class="mb-3">
        <label for="amd_usage" class="form-label">AMF Usage</label>
        <select id="amd_usage" class="form-select" v-model="config.amd_usage">
          <option value="transcoding">transcoding -- transcoding (slowest)</option>
          <option value="webcam">webcam -- webcam (slow)</option>
          <option value="lowlatency">lowlatency - low latency (fast)</option>
          <option value="ultralowlatency">ultralowlatency - ultra low latency (fastest)</option>
        </select>
      </div>
      <div class="mb-3">
        <label for="amd_preanalysis" class="form-label">AMF Preanalysis</label>
        <select id="amd_preanalysis" class="form-select" v-model="config.amd_preanalysis">
          <option value="enabled">enabled</option>
          <option value="disabled">disabled (default)</option>
        </select>
      </div>
      <div class="mb-3">
        <label for="amd_vbaq" class="form-label">AMF Variance Based Adaptive Quantization (VBAQ)</label>
        <select id="amd_vbaq" class="form-select" v-model="config.amd_vbaq">
          <option value="enabled">enabled (default)</option>
          <option value="disabled">disabled</option>
        </select>
      </div>
      <div class="mb-3">
        <label for="amd_coder" class="form-label">AMF Coder (H264)</label>
        <select id="amd_coder" class="form-select" v-model="config.amd_coder">
          <option value="auto">auto -- let ffmpeg decide (default)</option>
          <option value="cabac">cabac -- context adaptive variable-length coding - higher quality</option>
          <option value="cavlc">cavlc -- context adaptive binary arithmetic coding - faster decode</option>
        </select>
      </div>
    </div>
    <!--VA-API Encoder Settings-->
    <div v-if="currentTab === 'va-api'" class="config-page">
      <input
        class="form-control"
        id="adapter_name"
        placeholder="/dev/dri/renderD128"
        v-model="config.adapter_name"
      />
    </div>
    <!--VideoToolbox Encoder Settings-->
    <div v-if="currentTab === 'vt'" class="config-page">
      <!--Presets-->
      <div class="mb-3">
        <label for="vt_coder" class="form-label">VideoToolbox Coder</label>
        <select id="vt_coder" class="form-select" v-model="config.vt_coder">
          <option value="auto">auto</option>
          <option value="cabac">cabac</option>
          <option value="cavlc">cavlc</option>
        </select>
      </div>
      <div class="mb-3">
        <label for="vt_software" class="form-label">VideoToolbox Software Encoding</label>
        <select id="vt_software" class="form-select" v-model="config.vt_software">
          <option value="auto">auto</option>
          <option value="disabled">disabled</option>
          <option value="allowed">allowed</option>
          <option value="forced">forced</option>
        </select>
      </div>
      <div class="mb-3">
        <label for="vt_realtime" class="form-label">VideoToolbox Realtime Encoding</label>
        <select id="vt_realtime" class="form-select" v-model="config.vt_realtime">
          <option value="enabled">enabled</option>
          <option value="disabled">disabled</option>
        </select>
      </div>
    </div>
  </div>
  <div class="alert alert-success my-4" v-if="saved && !restarted">
    <i class="fa-solid fa-xl fa-circle-check"></i> Click 'Apply' to restart Sunshine and apply changes.
    This will terminate any running sessions.
  </div>
  <div class="alert alert-primary my-4" v-if="restarted">
    <i class="fa-solid fa-xl fa-spinner fa-spin"></i> Sunshine is restarting to apply changes.
  </div>
  <div class="mb-3 buttons">
    <button class="btn btn-primary" @click="save">Save</button>
    <button class="btn btn-success" @click="apply" v-if="saved && !restarted">Apply</button>
  </div>
</div>

<script>
  // create dictionary for defaultConfig
  const defaultConfig = {
    "address_family": "ipv4",
    "always_send_scancodes": "enabled",
    "amd_coder": "auto",
    "amd_preanalysis": "disabled",
    "amd_quality": "balanced",
    "amd_rc": "vbr_latency",
    "amd_usage": "ultralowlatency",
    "amd_vbaq": "enabled",
    "capture": "",
    "controller": "enabled",
    "install_steam_audio_drivers": "enabled",
    "dwmflush": "enabled",
    "encoder": "",
    "fps": "[10,30,60,90,120]",
    "gamepad": "auto",
    "hevc_mode": 0,
    "av1_mode": 0,
    "key_rightalt_to_key_win": "disabled",
    "keyboard": "enabled",
    "min_log_level": 2,
    "mouse": "enabled",
    "nvenc_h264_cavlc": "disabled",
    "nvenc_preset": "1",
    "nvenc_realtime_hags": "enabled",
    "nvenc_twopass": "quarter_res",
    "origin_web_ui_allowed": "lan",
    "qsv_coder": "auto",
    "qsv_preset": "medium",
    "resolutions": "[352x240,480x360,858x480,1280x720,1920x1080,2560x1080,3440x1440,1920x1200,3840x2160,3840x1600]",
    "sw_preset": "superfast",
    "sw_tune": "zerolatency",
    "upnp": "disabled",
    "vt_coder": "auto",
    "vt_realtime": "enabled",
    "vt_software": "auto",
    "global_prep_cmd": "[]",
  }

  new Vue({
    el: "#app",
    data() {
      return {
        platform: "",
        saved: false,
        restarted: false,
        config: null,
        fps: [],
        resolutions: [],
        currentTab: "general",
        resIn: "",
        fpsIn: "",
        global_prep_cmd: [],
        tabs: [
          {
            id: "general",
            name: "General",
          },
          {
            id: "files",
            name: "Files",
          },
          {
            id: "input",
            name: "Input",
          },
          {
            id: "av",
            name: "Audio/Video",
          },
          {
            id: "advanced",
            name: "Advanced",
          },
          {
            id: "nv",
            name: "NVIDIA NVENC Encoder",
          },
          {
            id: "qsv",
            name: "Intel QuickSync Encoder",
          },
          {
            id: "amd",
            name: "AMD AMF Encoder",
          },
          {
            id: "va-api",
            name: "VA-API Encoder",
          },
          {
            id: "vt",
            name: "VideoToolbox Encoder",
          },
          {
            id: "sw",
            name: "Software Encoder",
          },
        ],
      };
    },
    created() {
      fetch("/api/config")
        .then((r) => r.json())
        .then((r) => {
          this.config = r;
          this.platform = this.config.platform;

          var app = document.getElementById("app");
          if (this.platform === "windows") {
            this.tabs = this.tabs.filter((el) => {
              return el.id !== "va-api" && el.id !== "vt";
            });
          }
          if (this.platform === "linux") {
            this.tabs = this.tabs.filter((el) => {
              return el.id !== "amd" && el.id !== "qsv" && el.id !== "vt";
            });
          }
          if (this.platform === "macos") {
            this.tabs = this.tabs.filter((el) => {
              return el.id !== "amd" && el.id !== "nv" && el.id !== "qsv" && el.id !== "va-api";
            });
          }

          // remove values we don't want in the config file
          delete this.config.platform;
          delete this.config.status;
          delete this.config.version;
          //Populate default values if not present in config
          for (let key in defaultConfig) {
            if (this.config[key] === undefined) {
              this.config[key] = defaultConfig[key]
            }
          }

          this.fps = JSON.parse(this.config.fps);
          //Resolutions should be fixed because are not valid JSON
          let res = this.config.resolutions.substring(
            1,
            this.config.resolutions.length - 1
          );
          let resolutions = [];
          res.split(",").forEach((r) => resolutions.push(r.trim()));
          this.resolutions = resolutions;
          
          this.config.global_prep_cmd = this.config.global_prep_cmd || [];
          this.global_prep_cmd = JSON.parse(this.config.global_prep_cmd);
        });
    },
    methods: {
      forceUpdate() {
        this.$forceUpdate()
      },
      serialize() {
        let nl = this.config === "windows" ? "\r\n" : "\n";
        this.config.resolutions =
          "[" +
          nl +
          "    " +
          this.resolutions.join("," + nl + "    ") +
          nl +
          "]";
        // remove quotes from values in fps
        this.config.fps = JSON.stringify(this.fps).replace(/"/g, "");
        this.config.global_prep_cmd = JSON.stringify(this.global_prep_cmd);
      },
      save() {
        this.saved = false;
        this.restarted = false;
        this.serialize();

        // create a temp copy of this.config to use for the post request
        let config = JSON.parse(JSON.stringify(this.config))

        // delete default values from this.config
        for (let key in defaultConfig) {
          let delete_value = false
          if (key === "resolutions" || key === "fps") {
            let regex = /([\d]+x[\d]+)/g
            // Use a regular expression to find each value and replace it with a quoted version

            let config_value = JSON.parse(config[key].replace(regex, '"$1"')).toString()
            let default_value = JSON.parse(defaultConfig[key].replace(regex, '"$1"')).toString()

            if (config_value === default_value) {
              delete_value = true
            }
          }

          if (config[key] === defaultConfig[key]) {
            delete_value = true
          }

          if (delete_value) {
            delete config[key]
          }
        }

        return fetch("/api/config", {
          method: "POST",
          body: JSON.stringify(config),
        }).then((r) => {
          if (r.status === 200) {
            this.saved = true
            return this.saved
          }
          else {
            return false
          }
        });
      },
      apply() {
        this.saved = this.restarted = false;
        let saved = this.save();

        saved.then((result) => {
          if (result === true) {
            this.restarted = true;
            setTimeout(() => {
              this.saved = this.restarted = false;
            }, 5000);
            fetch("/api/restart", {
              method: "POST"
            });
          }
        });
      },
      add_global_prep_cmd() {
        let template = {
          do: "",
          undo: "",
        };

        if(this.platform === 'windows'){
          template = {...template, elevated: false};
        }
        this.global_prep_cmd.push(template);
      },
    },
    computed: {
      effectivePort() {
        // Convert config.port to a number.
        const port = +this.config?.port

        // Check if port is NaN or a falsy value (like 0, empty string, etc.).
        // If so, default to config port. Otherwise, use the value of port.
        return port ? port : 47989
      },
    }
  });
</script>

<style>
  .config-page {
    padding: 1em;
    border: 1px solid #dee2e6;
    border-top: none;
  }

  .buttons {
    padding: 1em 0;
  }

  .ms-item {
    background-color: #ccc;
    font-size: 12px;
    font-weight: bold;
  }
</style>
